home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / info-service / gopher / Unix / GopherTools / glog / glog30.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-08  |  26.2 KB  |  1,139 lines

  1.  
  2. /* Define DETAIL if you want detail listings to be kept, this can
  3.  * double the pointer memory required and slow things down.  If you NEVER
  4.  * want to do DETAIL listings then undefine it.  On fast machines it really
  5.  * doesn't matter, but on my Amiga I can notice the difference.  You need
  6.  * about 1.5 times the size of you log file in memory.
  7.  */
  8.  
  9. #define DETAIL
  10.  
  11. /*** glog 3.0 ***/
  12.  
  13. /*** glog.c -- analysis    tool for Unix gopherd logs ***/
  14.  
  15. /*** Version 3.0 
  16.  *** by: Andy Wick - awick@csugrad.cs.vt.edu
  17.  *** This version is an almost TOTAL rewrite of glog.  It now reads all
  18.  *** the information into memory before it does ANYTHING.  It then goes
  19.  *** through the arguments one at a time.  So inorder to effect something
  20.  *** you must change it before the report.  ie.  Argument order matters now.
  21.  ***
  22.  *** Version 2.2
  23.  *** by: Chuck Shotton - cshotton@oac.hsc.uth.tmc.edu
  24.  ***
  25.  *** Version 2.1 
  26.  *** by: Michael Mealling - Georgia Institute of Technology
  27.  ***       Office of Information Technology
  28.  ***       michael.meallingl@oit.gatech.edu
  29.  ***       12/29/92
  30.  ***
  31.  *** Versions 1.0
  32.  *** by: Chuck Shotton - U of Texas Health Science Center - Houston,
  33.  ***    Office    of Academic Computing
  34.  ***    cshotton@oac.hsc.uth.tmc.edu
  35.  ***    6/17/92
  36.  ***/
  37.  
  38.  
  39. #include <stdio.h>
  40. #include <string.h>
  41. #include <stdlib.h>
  42. #ifdef THINK_C
  43. #include <console.h>
  44. #endif
  45.  
  46. #define    GLOG_VERSION "Gopher Log Analyzer v.3.0"
  47.  
  48. /* GENERAL STUFF */
  49. typedef unsigned char byte;
  50.  
  51. /* Error log link list */
  52. typedef    struct enode_list {
  53.     char      *data;
  54.     struct enode_list *next;
  55. } ELIST_REC, *ELIST_PTR;
  56.  
  57. /* GOPHER LINE STUFF */
  58.  
  59. /* These are the different types of data that are currenly reconized*/
  60. #define FILETYPE    ' '
  61. #define DIRTYPE        'D'
  62. #define MAILDIRTYPE    'M'
  63. #define FTPTYPE        'F'
  64. #define RANGETYPE    'R'
  65.  
  66. /* One line of the gopher log is stored in here */
  67. typedef struct gopher_line {
  68.    byte     day;
  69.    byte     month;
  70.    short     date;
  71.    char     *hostname;
  72.    char     *path;
  73.    char     type;
  74. } GOPHER_REC, *GOPHER_PTR;
  75.  
  76. /* A Linked list of gopher lines */
  77. typedef    struct node_list {
  78.     GOPHER_PTR      data;
  79.         short         hits;
  80.     struct node_list *next;
  81. }  LIST_REC, *LIST_PTR;
  82.  
  83.  
  84. /* Main tree */
  85. typedef    struct node_rec    {
  86.     GOPHER_PTR    data;
  87. #ifdef DETAIL
  88.     LIST_REC     *llist;
  89. #endif
  90.         short         hits;
  91.     struct node_rec    *left, *right;
  92. } NODE_REC, *NODE_PTR;
  93.  
  94. /***
  95.  *** The cruft list is a general list for things that aren't parse-able    by
  96.  *** ProcessLine().  "cruft" kept for historical reasons.
  97.  ***/
  98. ELIST_PTR     cruft = NULL;
  99.  
  100. /***
  101.  *** The following lists are maintained.
  102.  ***/
  103. NODE_PTR     hosts = NULL;
  104. NODE_PTR     docs  = NULL;
  105. NODE_PTR     days  = NULL;
  106. NODE_PTR     dates = NULL;
  107. NODE_PTR     types = NULL;
  108.  
  109. /***
  110.  *** The following macro is used to insert things into the above lists
  111.  *** If you add a new sorting type, don't forget to add it here.
  112.  ***/
  113. #define ADDDATA(data) hosts = Insert(hosts, data, HostsCmp); \
  114.                       docs  = Insert(docs, data, DocsCmp); \
  115.                       dates = Insert(dates, data, DatesCmp); \
  116.                       types = Insert(types, data, TypesCmp); \
  117.                       days  = Insert(days, data, DaysCmp);
  118.  
  119. /***
  120.  *** Self-Documenting vars, that save memory
  121.  ***/
  122. char         *ROOTNAME = "Root Connections";
  123. char        *Days[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
  124. char        *Months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  125.                    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  126.  
  127. /* The base file name for gnuplot reports */
  128. char BASE[7] = "gopher";
  129. char *base = BASE;
  130.  
  131. /* Plot Output */
  132. #define REPORTOUT    0
  133. #define GNUOUT         1
  134. #define HISTOUT        2
  135.  
  136. /* Type of plot to do */
  137. char OutPlot=GNUOUT;
  138.  
  139. /* Used to tell the Plot routines that you are starting and stoping */
  140. #define PLOTSTART    (GOPHER_PTR)0
  141. #define PLOTDONE    (GOPHER_PTR)1
  142.  
  143. /* Width of reports */
  144. byte     Width = 62; /* 80 - WIDTHSUB */
  145. #define WIDTHSUB     18 /* The width of the standard print stuff */
  146.  
  147. /* Information */
  148.    /* Internal */
  149. #define NOINFO        0
  150. #define DETAILINFO    1
  151.    /* Error log requested, but not a valid SORT TYPE */
  152. #define ERRORINFO    'E'
  153.    /* SORT TYPES */
  154.    /* Changing these will change the options also */
  155. #define DATAINFO     'D'
  156. #define HOSTINFO    'H'
  157. #define WEEKDAYINFO    'W'
  158. #define MONTHDATEINFO    'M'
  159. #define TYPEINFO    'T'
  160.  
  161.  
  162. /* The only forward decleration needed, since I wrote this the pascal way,
  163.    the way all programs should be written.  You don't need all the stupid
  164.    forward declerations, or prototypes. */
  165. void PrintInfo(NODE_PTR tree, void print(GOPHER_PTR), int cmp(GOPHER_PTR a, GOPHER_PTR b), byte DetailType);
  166.  
  167.  
  168. /*******************************/
  169. /* Add item to error log */
  170. ELIST_PTR InsertErrorLog(ELIST_PTR list, char *data)
  171. {
  172. ELIST_PTR temp, temp2;
  173.  
  174.    if (NULL == (temp = (ELIST_PTR)malloc(sizeof(ELIST_REC))))
  175.    {
  176.       fprintf(stderr, "Not enough memory to add to ErrorLog\n");
  177.       exit(1);
  178.    }
  179.    if (NULL == (temp->data = (char *)malloc(sizeof(char) * (strlen(data) +1))))
  180.    {
  181.       fprintf(stderr, "Not enough memory to add to ErrorLog\n");
  182.       exit(1);
  183.    }
  184.    strcpy(temp->data, data);
  185.    temp->next = NULL;
  186.  
  187.    if (list == NULL)
  188.       return (temp);
  189.  
  190.    for (temp2 = list; temp2->next != NULL ; temp2 = temp2->next);
  191.    temp2->next = temp;
  192.  
  193.    return(list);
  194. }
  195. #ifdef DETAIL
  196. /*******************************/
  197. LIST_PTR InsertDetail(LIST_PTR list, GOPHER_PTR data)
  198. {
  199. LIST_PTR temp;
  200.  
  201.       if (NULL == (temp = (LIST_PTR)malloc(sizeof(LIST_REC))))
  202.       {
  203.          fprintf(stderr, "Not enough memory to add to DetailList\n");
  204.          exit(1);
  205.       }
  206.       temp->data = data;
  207.       temp->next = list;
  208.       temp->hits = 1;
  209.       return(temp);
  210. }
  211. #endif
  212. /*******************************/
  213. /* Insert tree_element into the    appropriate symbol table. Increment the    */
  214. /* number of hits if that element is already present.   */
  215. /* Insert list_element into linked list    contained in the node that    */
  216. /* tree_element    was put    in.      */
  217.  
  218. NODE_PTR Insert(NODE_PTR tree, GOPHER_PTR data, int cmp(GOPHER_PTR a, GOPHER_PTR b))
  219. {
  220. int i;
  221.  
  222.    if (tree == NULL)
  223.    {
  224.       if (NULL == (tree = (NODE_PTR) malloc(sizeof(NODE_REC))))
  225.       {
  226.          fprintf(stderr, "No memory for InsertHost\n");
  227.      exit(1);
  228.       }
  229.       tree->data = data;
  230.       tree->left = tree->right = NULL;
  231. #ifdef DETAIL
  232.       tree->llist = InsertDetail(NULL, data);
  233. #endif
  234.       tree->hits = 1;
  235.       return(tree);
  236.    }
  237.  
  238.    i=cmp(data, tree->data);
  239.  
  240.    if (i > 0)
  241.       tree->right = Insert(tree->right, data, cmp);
  242.    else if (i<0) 
  243.       tree->left = Insert(tree->left, data, cmp);
  244.    else
  245.    {
  246.       tree->hits += 1;
  247. #ifdef DETAIL
  248.       tree->llist = InsertDetail(tree->llist, data);
  249. #endif
  250.    }
  251.  
  252.    return(tree);
  253. }
  254.  
  255. /*******************************/
  256. NODE_PTR Find(NODE_PTR tree, GOPHER_PTR data, int cmp(GOPHER_PTR a, GOPHER_PTR b))
  257. {
  258. int i;
  259.  
  260.    if (tree == NULL)
  261.    {
  262.       return (NULL);
  263.    }
  264.  
  265.    i=cmp(data, tree->data);
  266.  
  267.    if (i > 0)
  268.       return(Find(tree->right, data, cmp));
  269.    if (i<0) 
  270.       return(Find(tree->left, data, cmp));
  271.  
  272.    return(tree);
  273. }
  274. /*******************************/
  275. /* Get a single field from temp, and return the new spot */
  276. char *getf(char *temp, char *field)
  277. {
  278.    while(*temp == ' ')
  279.       temp++;
  280.  
  281.    *field = '\0';
  282.    if (*temp == '\n')
  283.       return(temp);
  284.  
  285.    while ((*temp != ' ') && (*temp != '\0'))
  286.      *field++ = *temp++;
  287.  
  288.    *field = '\0';
  289.    return(temp);
  290. }
  291.  
  292. /*******************************/
  293. int TypesCmp(GOPHER_PTR a, GOPHER_PTR b)
  294. {
  295.    return(a->type - b->type);
  296. }
  297. /*******************************/
  298. int HostsCmp(GOPHER_PTR a, GOPHER_PTR b)
  299. {
  300.    return(strcmp(a->hostname, b->hostname));
  301. }
  302. /*******************************/
  303. int DocsCmp(GOPHER_PTR a, GOPHER_PTR b)
  304. {
  305.    return(strcmp(a->path, b->path));
  306. }
  307. /*******************************/
  308. int DaysCmp(GOPHER_PTR a, GOPHER_PTR b)
  309. {
  310.    return(a->day - b->day);
  311. }
  312. /*******************************/
  313. int DatesCmp(GOPHER_PTR a, GOPHER_PTR b)
  314. {
  315. int i = a->month - b->month;
  316.    if (i == 0)
  317.       return(a->date - b->date);
  318.    else
  319.       return(i); 
  320. }
  321. /*******************************/
  322. byte MonthStr2Num(char *str)
  323. {
  324. static char lastmonth[4] = "Jan"; /* Who knows if saving the last month */
  325. static int lastmonthnum = 1;      /* really makes it faster */
  326. int i;
  327.  
  328.    if (strcmp(lastmonth, str) == 0)
  329.       return(lastmonthnum);
  330.  
  331.    for(i=0;i<12;i++)
  332.       if (strcmp(Months[i], str) == 0)
  333.       {
  334.          strcpy(lastmonth, Months[i]);
  335.      lastmonthnum = i+1;
  336.      return(lastmonthnum);
  337.       }
  338.    return(13); 
  339. }
  340. /*******************************/
  341. byte DayStr2Num(char *str)
  342. {
  343. static char lastday[4] = "Sun"; /* Same here.  Is there a better way? */
  344. static int lastdaynum = 1;
  345. int i;
  346.  
  347.    if (strcmp(lastday, str) == 0)
  348.       return(lastdaynum);
  349.  
  350.    for(i=0;i<7;i++)
  351.       if (strcmp(Days[i], str) == 0)
  352.       {
  353.          strcpy(lastday, Days[i]);
  354.      lastdaynum = i+1;
  355.      return(lastdaynum);
  356.       }
  357.    return(8); 
  358. }
  359. /*******************************/
  360. /* Read    a line from the    log file, parse    it up, and insert the */
  361. /* info    into the appropriate tables.         */
  362.  
  363. void ProcessLine(char *line)
  364. {
  365. GOPHER_PTR data;
  366. short len;
  367. char *temp; /* Used to save line, incase it is needed for cruft */
  368. char junk[1025];
  369. char message1[128];
  370. char message2[128];
  371.  
  372.    if (NULL == (data = (GOPHER_PTR)malloc(sizeof(GOPHER_REC))))
  373.    {
  374.       fprintf(stderr, "Not enough memory. Sorry\n");
  375.       exit(1);
  376.    }
  377.  
  378.    temp = line;
  379.  
  380.    temp = getf(temp, junk); /* Day */
  381.    if (8 == (data->day = DayStr2Num(junk))) 
  382.    { /* Not a real day of week */
  383.       free(data);
  384.       cruft = InsertErrorLog(cruft, line);
  385.       return;
  386.    }
  387.    temp = getf(temp, junk); /* Month */
  388.    if (13 == (data->month = MonthStr2Num(junk)))
  389.    { /* Not a real month */
  390.       free(data);
  391.       cruft = InsertErrorLog(cruft, line);
  392.       return;
  393.    }
  394.    temp = getf(temp, junk); /* Date */
  395.    data->date = atoi(junk);
  396.    temp = getf(temp, junk);
  397.    temp = getf(temp, junk);
  398.    temp = getf(temp, junk);
  399.    temp = getf(temp ,junk); /* hostname */
  400.    if (junk[0] == ':')
  401.    { /* A colon in the hostfield */
  402.       free(data);
  403.       cruft = InsertErrorLog(cruft, line);
  404.       return;
  405.    } 
  406.    if (NULL == (data->hostname = (char *)malloc(sizeof(char) * (strlen(junk)+1))))
  407.    {
  408.       fprintf(stderr, "Not enough memory. Sorry\n");
  409.       exit(1);
  410.    }
  411.    strcpy(data->hostname, junk);
  412.  
  413.    temp = getf(temp, junk); /* : COLON */
  414.    if (junk[0] != ':')
  415.    { /* Now we don't have a colon */
  416.       free(data->hostname);
  417.       free(data);
  418.       cruft = InsertErrorLog(cruft, line);
  419.       return;
  420.    } 
  421.    temp = getf(temp, message1);
  422.    temp = getf(temp, message2);
  423.    while((*temp == ' ') && (*temp != '\0'))
  424.        temp++;
  425.    data->path = (char *)malloc(sizeof(char)*(strlen(temp)+1));
  426.    strcpy(data->path, temp);
  427.    data->path[strlen(temp)] = '\0';
  428.  
  429.  
  430.    if (0 != (len = strlen(data->path)))
  431.    {
  432.       if (data->path[len-1] == '\n')
  433.          data->path[len-1] = '\0';
  434.    }
  435.  
  436. /***
  437.  *** This one is for that annoying 0.0.0.* IP address then gets    stuck
  438.  *** in    the log    when someone is    trying to access something you ain't got
  439.  ***/
  440.  
  441.    if (strncmp(data->hostname,"0.0.0", 5) == 0)
  442.    { 
  443.       free(data->path);
  444.       free(data->hostname);
  445.       free(data);
  446.       cruft = InsertErrorLog(cruft, line);
  447.       return;
  448.    } 
  449.  
  450.    if (strcmp(message1, "Root") == 0)
  451.    {
  452.       data->type = DIRTYPE;
  453.       free(data->path);
  454.       data->path = ROOTNAME;
  455.       ADDDATA(data);
  456.    }
  457.    else if ((strcmp(message1, "retrieved") == 0) && (strcmp(data->path, "/") == 0))
  458.    {
  459.       data->type = DIRTYPE;
  460.       free(data->path);
  461.       data->path = ROOTNAME;
  462.       ADDDATA(data);
  463.    }
  464.    else if (strncmp(message2, "ftp:", 4) == 0)
  465.    {
  466.       strcpy(junk, data->path); /* Incase there was a space in the path */
  467.       free(data->path); /* Then we have to save off path, since it contains it*/
  468.       data->path = (char *)malloc(sizeof(char)*(strlen(message2)+strlen(junk)));
  469.       strcpy(data->path, message2+4);
  470.       strcat(data->path, junk);
  471.       data->type = FTPTYPE;
  472.  
  473.       ADDDATA(data);
  474.    }
  475.    else if (strcmp(message1, "retrieved") == 0)
  476.    {
  477.       if (data->path[0] == '\0')
  478.       { /* We some how retrieved nothing */
  479.          free(data->path);
  480.          free(data->hostname);
  481.          free(data);
  482.          cruft = InsertErrorLog(cruft, line);
  483.          return;
  484.       } 
  485.  
  486.       if (strcmp(message2, "directory") == 0)
  487.          data->type = DIRTYPE;
  488.       else if (strcmp(message2, "maildir") == 0)
  489.          data->type = MAILDIRTYPE;
  490.       else if (strcmp(message2, "file") == 0)
  491.          data->type = FILETYPE;
  492.       else if (strcmp(message2, "range") == 0)
  493.          data->type = RANGETYPE;
  494.       else
  495.       {
  496.          free(data->path);
  497.          free(data->hostname);
  498.          free(data);
  499.          cruft = InsertErrorLog(cruft, line);
  500.          return;
  501.       } 
  502.       ADDDATA(data);
  503.  
  504.    }
  505.    else /* wasn't anything we know about, g+ maybe?*/
  506.    {
  507.       free(data->path);
  508.       free(data->hostname);
  509.       free(data);
  510.       cruft = InsertErrorLog(cruft, line);
  511.       return;
  512.    } 
  513.    return;
  514. }
  515.  
  516. /*******************************/
  517. void GatherInfo(void)
  518. {
  519. char line[1025];
  520.  
  521.    while(!feof(stdin))
  522.    {
  523.       fgets(line, 1024, stdin);
  524.       if (feof(stdin))
  525.          break;
  526.       ProcessLine(line);
  527.    }
  528. }
  529.  
  530. /*******************************/
  531.  
  532. /* These vars are only valid right after a call to TreeTo?List.  I could have
  533.  *  done some fancy var passing, but why bother. :) */
  534. LIST_PTR GByNum;
  535. int GByNumHits;
  536. int GByNumMin; /* These two will be used for histograms in the future */
  537. int GByNumMax;
  538.     
  539.  
  540. /*******************************/
  541. void InsertSByNum(GOPHER_PTR data, short hits)
  542. {
  543. LIST_PTR temp, temp2;
  544.  
  545.    if (NULL == (temp = (LIST_PTR)malloc(sizeof(LIST_REC))))
  546.    {
  547.       fprintf(stderr, "Not enough memory in InsertByNum\n");
  548.       exit(1);
  549.    }
  550.    temp->data = data;
  551.    temp->next = NULL;
  552.    temp->hits = hits;
  553.  
  554. /* Figure out some vars */
  555.    if (hits < GByNumMin)
  556.       GByNumMin = hits;
  557.    if (hits > GByNumMax)
  558.       GByNumMax = hits;
  559.    GByNumHits += temp->hits;
  560.  
  561.    if (GByNum == NULL)
  562.       GByNum = temp;
  563.  
  564.    else if (GByNum->hits < hits)
  565.    {
  566.       temp->next = GByNum;
  567.       GByNum = temp;
  568.    }
  569.    else
  570.    {
  571.       temp2 = GByNum;
  572.       while (temp2->next != NULL)
  573.       {
  574.          if (temp2->next->hits < hits)
  575.      {
  576.         temp->next = temp2->next;
  577.         temp2->next = temp;
  578.         return;
  579.      }
  580.      temp2 = temp2->next;
  581.       }
  582.       temp2->next = temp;
  583.    }
  584. }
  585.  
  586. /*******************************/
  587. void InsertUByNum(GOPHER_PTR data, short hits)
  588. {
  589. LIST_PTR temp;
  590.  
  591.    if (NULL == (temp = (LIST_PTR)malloc(sizeof(LIST_REC))))
  592.    {
  593.       fprintf(stderr, "Not enough memory in InsertByNum\n");
  594.       exit(1);
  595.    }
  596.    temp->data = data;
  597.    temp->next = NULL;
  598.    temp->hits = hits;
  599.  
  600. /* Figure out some vars */
  601.    if (hits < GByNumMin)
  602.       GByNumMin = hits;
  603.    if (hits > GByNumMax)
  604.       GByNumMax = hits;
  605.    GByNumHits += temp->hits;
  606.  
  607.    if (GByNum == NULL)
  608.       GByNum = temp;
  609.  
  610.    else
  611.    {
  612.       temp->next = GByNum;
  613.       GByNum = temp;
  614.    }
  615. }
  616.  
  617. /*******************************/
  618. /* I did two different routines so it would be faster :).  I know this
  619.  * doesn't follow the logic of the rest of the program, but oh well.
  620.  * Do Inorder so that they remain in order, if two have the same
  621.  * num of hits 
  622.  */
  623. void TreeToSList(NODE_PTR tree)
  624. {
  625.    if (tree == NULL)
  626.       return;
  627.    
  628.    TreeToSList(tree->left);
  629.    InsertSByNum(tree->data, tree->hits);
  630.    TreeToSList(tree->right);
  631. }
  632.  
  633. /*******************************/
  634. void TreeToUList(NODE_PTR tree)
  635. {
  636. /* I did two different routines so it would be faster :).  I know this
  637.  * doesn't follow the logic of the rest of the program, but oh well.
  638.  * Do reverse inorder, so the insert just basicly sticks it at the
  639.  * beginning.  Someone should rewrite this, maybe later :)
  640.  */
  641.    if (tree == NULL)
  642.       return;
  643.    
  644.    TreeToUList(tree->right);
  645.    InsertUByNum(tree->data, tree->hits);
  646.    TreeToUList(tree->left);
  647. }
  648.  
  649. /*******************************/
  650. NODE_PTR ListToTree(LIST_PTR list, int cmp(GOPHER_PTR, GOPHER_PTR))
  651. {
  652. NODE_PTR temptree = NULL;
  653.    for(;list != NULL; list = list->next)
  654.       temptree = Insert(temptree, list->data, cmp);
  655.    return(temptree);
  656. }
  657. /*******************************/
  658. void FreeList(LIST_PTR list)
  659. {
  660. LIST_PTR temp;
  661.    while (list != NULL)
  662.    {
  663.       temp = list;
  664.       list = list->next;
  665.       free(temp);
  666.    }
  667. }
  668. /*******************************/
  669. void FreeTree(NODE_PTR tree)
  670. {
  671.    if (tree == NULL)
  672.       return;
  673.    FreeTree(tree->left);
  674.    FreeTree(tree->right);
  675. #ifdef DETAIL
  676.    FreeList(tree->llist);
  677. #endif
  678.    free(tree);
  679.    return;
  680. }
  681. /*******************************/
  682. /* Given a string and and len, left justify and fill with spaces */
  683. void printl(char *str, int len)
  684. {
  685.    while (len > 0)
  686.    {
  687.       if (*str == '\n')
  688.          str++;
  689.       if (*str == '\0')
  690.      putc(' ', stdout);
  691.       else
  692.          putc(*str++, stdout);
  693.       len--;
  694.    }
  695. }
  696. /*******************************/
  697. void PrintData(GOPHER_PTR data)
  698. {
  699.    if (data == NULL)
  700.    {
  701.       printf("Data:\n");
  702.    }
  703.    else
  704.    {
  705.       printf("%c ",data->type);
  706.       printl(data->path, Width - 2);
  707.    }
  708. }
  709. /*******************************/
  710. void PrintType(GOPHER_PTR data)
  711. {
  712. char *temp;
  713.    if (data == NULL)
  714.    {
  715.       printf("Types:\n");
  716.    }
  717.    else
  718.    {
  719.       switch(data->type)
  720.       {
  721.      case FILETYPE:
  722.         temp = "File";
  723.         break;
  724.      case DIRTYPE:
  725.         temp = "Directory";
  726.         break;
  727.      case MAILDIRTYPE:
  728.         temp = "Mail Directory";
  729.         break;
  730.      case FTPTYPE:
  731.         temp = "FTP";
  732.         break;
  733.      case RANGETYPE:
  734.         temp = "Range";
  735.         break;
  736.       }
  737.       printl(temp, Width);
  738.    }
  739. }
  740. /*******************************/
  741. void PrintHost(GOPHER_PTR data)
  742. {
  743.    if (data == NULL)
  744.    {
  745.       printf("Hosts:\n");
  746.    }
  747.    else
  748.    {
  749.       printl(data->hostname, Width);
  750.    }
  751.  
  752. }
  753. /*******************************/
  754. void PrintDay(GOPHER_PTR data)
  755. {
  756.    if (data == NULL)
  757.    {
  758.       printf("Days:\n");
  759.    }
  760.    else
  761.    {
  762.       printl(Days[data->day-1], Width);
  763.    }
  764. }
  765. /*******************************/
  766. void PrintDate(GOPHER_PTR data)
  767. {
  768.    if (data == NULL)
  769.    {
  770.       printf("Dates:\n");
  771.    }
  772.    else
  773.    {
  774.       printf("%3s %3s %2d", Days[data->day-1], Months[data->month-1], data->date);
  775.       printl("\0", Width - 10);
  776.    }
  777. }
  778. /*******************************/
  779. void PlotData(FILE *rfp, int num, GOPHER_PTR data)
  780. {
  781.    if (data == PLOTSTART)
  782.    {
  783.       fprintf(stderr, "Plot of Data is not currently supported, since I am not quite sure what it is suppose to do.  Mail me ideas: awick@csugrad.cs.vt.edu\n");
  784.  
  785.    }
  786.  
  787. }
  788. /*******************************/
  789. void PlotType(FILE *rfp, int num, GOPHER_PTR data)
  790. {
  791. char *temp;
  792.    if (data == PLOTSTART)
  793.    {
  794.       fprintf(rfp,"set xtics (");
  795.    }
  796.    else if (data == PLOTDONE)
  797.    {
  798.       fprintf(rfp,"\"\" %d)\n", num);
  799.       fprintf(rfp,"set data style linespoints\n");
  800.       fprintf(rfp,"set tics out\n");
  801.       fprintf(rfp,"set grid\n");
  802.       fprintf(rfp,"set title \"Gopher Usage\"\n");
  803.       fprintf(rfp,"plot \"%s.dat\"\n", base);
  804.    }
  805.    else
  806.    {
  807.       switch(data->type)
  808.       {
  809.      case FILETYPE:
  810.         temp = "File";
  811.         break;
  812.      case DIRTYPE:
  813.         temp = "Directory";
  814.         break;
  815.      case MAILDIRTYPE:
  816.         temp = "Mail Directory";
  817.         break;
  818.      case FTPTYPE:
  819.         temp = "FTP";
  820.         break;
  821.      case RANGETYPE:
  822.         temp = "Range";
  823.         break;
  824.       }
  825.       fprintf(rfp,"\"%s\" %d,", temp, num);
  826.    }
  827.  
  828. }
  829. /*******************************/
  830. void PlotHost(FILE *rfp, int num, GOPHER_PTR data)
  831. {
  832.    if (data == PLOTSTART)
  833.    {
  834.       fprintf(stderr, "Plot of Hosts is not currently supported, since I am not quite sure what it is suppose to do.  Mail me ideas: awick@csugrad.cs.vt.edu\n");
  835.  
  836.    }
  837. }
  838. /*******************************/
  839. void PlotDay(FILE *rfp, int num, GOPHER_PTR data)
  840. {
  841.    if (data == PLOTSTART)
  842.    {
  843.       fprintf(rfp,"set xtics (");
  844.    }
  845.    else if (data == PLOTDONE)
  846.    {
  847.       fprintf(rfp,"\"\" %d)\n", num);
  848.       fprintf(rfp,"set data style linespoints\n");
  849.       fprintf(rfp,"set tics out\n");
  850.       fprintf(rfp,"set grid\n");
  851.       fprintf(rfp,"set title \"Gopher Usage\"\n");
  852.       fprintf(rfp,"plot \"%s.dat\"\n", base);
  853.    }
  854.    else
  855.    {
  856.       fprintf(rfp,"\"%s\" %d,",Days[data->day-1], num);
  857.    }
  858. }
  859. /*******************************/
  860. void PlotDate(FILE *rfp, int num, GOPHER_PTR data)
  861. {
  862.    if (data == PLOTSTART)
  863.    {
  864.       fprintf(rfp,"set xtics (");
  865.    }
  866.    else if (data == PLOTDONE)
  867.    {
  868.       fprintf(rfp,"\"\" %d)\n", num);
  869.       fprintf(rfp,"set data style linespoints\n");
  870.       fprintf(rfp,"set tics out\n");
  871.       fprintf(rfp,"set grid\n");
  872.       fprintf(rfp,"set title \"Gopher Usage\"\n");
  873.       fprintf(rfp,"plot \"%s.dat\"\n", base);
  874.    }
  875.    else
  876.    {
  877.       if ((data->date == 1) || (data->date == 15) || (num == 1))
  878.          fprintf(rfp,"\"%s/%d\" %d,",Months[data->month-1], data->date, num);
  879.    }
  880. }
  881. #ifdef DETAIL
  882. /*******************************/
  883. void DoDetail(NODE_PTR tree, byte DetailType)
  884. {
  885. NODE_PTR newtree;
  886.    switch(DetailType)
  887.    {
  888.    case DATAINFO:
  889.       newtree = ListToTree(tree->llist, DocsCmp);
  890.       PrintInfo(newtree, PrintData, DocsCmp, DETAILINFO);
  891.       break;
  892.    case HOSTINFO:
  893.       newtree = ListToTree(tree->llist, HostsCmp);
  894.       PrintInfo(newtree, PrintHost, HostsCmp, DETAILINFO);
  895.       break;
  896.    case WEEKDAYINFO:
  897.       newtree = ListToTree(tree->llist, DaysCmp);
  898.       PrintInfo(newtree, PrintDay, DaysCmp, DETAILINFO);
  899.       break;
  900.    case MONTHDATEINFO:
  901.       newtree = ListToTree(tree->llist, DatesCmp);
  902.       PrintInfo(newtree, PrintDate, DatesCmp, DETAILINFO);
  903.       break;
  904.    case TYPEINFO:
  905.       newtree = ListToTree(tree->llist, TypesCmp);
  906.       PrintInfo(newtree, PrintType, TypesCmp, DETAILINFO);
  907.       break;
  908.    }
  909.    FreeTree(newtree);
  910. }
  911. #endif
  912. /*******************************/
  913. void PrintInfo(NODE_PTR tree, void print(GOPHER_PTR), int cmp(GOPHER_PTR a, GOPHER_PTR b), byte DetailType)
  914. {
  915. LIST_PTR temp;
  916. LIST_PTR ByNum;
  917. int ByNumHits;
  918.  
  919.    if (DetailType != DETAILINFO)/*We are printing Detail info now,so no headers*/
  920.    {
  921.       print(NULL);
  922.       printf("=========================================================\n");
  923.    }
  924.    GByNum = NULL; /* Init the vars for the TreeToList function */
  925.    GByNumHits = 0;
  926.    TreeToSList(tree);
  927.  
  928.    ByNum = GByNum; /* Save off and clear the globals vars, since this */
  929.    ByNumHits = GByNumHits; /* function can be called recurisively */
  930.    GByNum = NULL;
  931.  
  932.    temp = ByNum;
  933.    while (temp != NULL)
  934.    {
  935. #ifdef DETAIL
  936.       if (DetailType == DETAILINFO)
  937.          printf("   ");
  938. #endif
  939.  
  940.       print(temp->data);
  941.       printf(" %4d (%2.2f%%)\n", temp->hits, (float)temp->hits*100.0/ByNumHits);
  942. #ifdef DETAIL
  943.       if ((DetailType != NOINFO) && (DetailType != DETAILINFO))
  944.          DoDetail(Find(tree, temp->data, cmp), DetailType);
  945.      /* Don't generate Detail for NOINFO or if we are already doing detail */
  946. #endif
  947.       temp = temp->next;
  948.    }
  949.    printf("\n");
  950.    FreeList(ByNum);
  951. }
  952. /*******************************/
  953. void PlotInfo(NODE_PTR tree, void plot(FILE *, int, GOPHER_PTR))
  954. {
  955. LIST_PTR temp;
  956. FILE *rfp, *dfp;
  957. char *fn;
  958. int points = 1;
  959.  
  960.    if (OutPlot == GNUOUT)
  961.    {
  962.       fn = (char *)malloc(strlen(base) + 5);
  963.       sprintf(fn,"%s.run", base);
  964.       if (NULL == (rfp = fopen(fn, "w")))
  965.       {
  966.          fprintf(stderr, "Could not open file \"%s\" for plot run\n", fn);
  967.          free(fn);
  968.      return;
  969.       }
  970.       sprintf(fn,"%s.dat", base);
  971.       if (NULL == (dfp = fopen(fn, "w")))
  972.       {
  973.          fprintf(stderr, "Could not open file \"%s\" for plot data\n", fn);
  974.          free(fn);
  975.      return;
  976.       }
  977.       free(fn);
  978.    }
  979.    else
  980.    {
  981.       rfp = stdout;
  982.       dfp = stdout;
  983.    }
  984.  
  985.    plot(rfp, 0, PLOTSTART);
  986.    GByNum = NULL; /* Init the vars for the TreeToList function */
  987.    GByNumHits = 0;
  988.    GByNumMax = 0;
  989.    GByNumMin = 36000;
  990.    TreeToUList(tree);
  991.  
  992.    temp = GByNum;
  993.    while (temp != NULL)
  994.    {
  995.       plot(rfp, points, temp->data);
  996.       fprintf(dfp, "%d %d\n", points++, temp->hits);
  997.       temp = temp->next;
  998.    }
  999.    plot(rfp, points, PLOTDONE);
  1000.    printf("\n");
  1001.    FreeList(GByNum);
  1002. }
  1003. /*******************************/
  1004. void PrintErrorInfo()
  1005. {
  1006. ELIST_PTR temp = cruft;
  1007.  
  1008.    printf("=========================================================\n");
  1009.    printf("Exception/Problem Report\n");
  1010.    printf("NOTE: THESE ENTRIES MAY DENOTE A SERVER PROBLEM. THEY SHOULD BE LOOKED OVER!\n");
  1011.    while (temp != NULL)
  1012.    {
  1013.       printf(temp->data);
  1014.       temp = temp->next;
  1015.    }
  1016.    printf("\n");
  1017. }
  1018.  
  1019. /*******************************/
  1020.  
  1021. void PrintHelp()
  1022. {
  1023. #ifdef DETAIL
  1024.    fprintf(stderr,"Usage: glog [-%ch] [-<SORTTYPE>[<SORTTYPE>]] [-p<SORTTYPE>]\n", ERRORINFO);
  1025. #else
  1026.    fprintf(stderr,"Usage: glog [-%ch] [-<SORTTYPE>] [-p<SORTTYPE>]\n", ERRORINFO);
  1027. #endif
  1028.        
  1029.    fprintf(stderr, "   [-w <width>] [-o <outputtype>] [-f <basefilename>]\n");
  1030.    fprintf(stderr, "  -%c = Error log         -h = this help\n", ERRORINFO);
  1031.    fprintf(stderr, "\n");
  1032.    fprintf(stderr, "SORTTYPE is one of the following\n");
  1033.    fprintf(stderr, "   %c = Host Names       %c = Day of Week \n",
  1034.       HOSTINFO, WEEKDAYINFO);
  1035.    fprintf(stderr, "   %c = Document Names   %c = Month/Day\n",
  1036.     DATAINFO, MONTHDATEINFO);
  1037.    fprintf(stderr, "   %c = Type\n", TYPEINFO);
  1038.    fprintf(stderr, "\n");
  1039. }
  1040. /*******************************/
  1041. int main(argc, argv)
  1042. int argc;
  1043. char **argv;
  1044. {
  1045. int i = 1;
  1046.  
  1047. #ifdef THINK_C
  1048.     argc = ccommand(&argv); 
  1049. #endif
  1050.  
  1051. #ifdef DETAIL    
  1052.    printf("%s with DETAIL\n", GLOG_VERSION);
  1053. #else
  1054.    printf("%s\n", GLOG_VERSION);
  1055. #endif
  1056.    fflush(stdout);
  1057.  
  1058.    if  (1 == argc)
  1059.    {
  1060.       PrintHelp(); /* Clueless */
  1061.       exit(-1);
  1062.    }
  1063.  
  1064.    GatherInfo();
  1065.    fflush(stdout);
  1066.    fflush(stderr);
  1067.  
  1068.    while (i<argc)
  1069.    {
  1070.       switch (argv[i][1])
  1071.       {
  1072.       case ERRORINFO:
  1073.      PrintErrorInfo();
  1074.      break;
  1075.       case DATAINFO:
  1076.      PrintInfo(docs, PrintData, DocsCmp, argv[i][2]);
  1077.      break;
  1078.       case TYPEINFO:
  1079.      PrintInfo(types, PrintType, TypesCmp, argv[i][2]);
  1080.      break;
  1081.       case WEEKDAYINFO:
  1082.          PrintInfo(days, PrintDay, DaysCmp, argv[i][2]);
  1083.      break;
  1084.       case MONTHDATEINFO:
  1085.      PrintInfo(dates, PrintDate, DatesCmp, argv[i][2]);
  1086.      break;
  1087.       case HOSTINFO:
  1088.      PrintInfo(hosts, PrintHost, HostsCmp, argv[i][2]);
  1089.      break;
  1090.       case 'p': /*custom plots*/
  1091.          switch (argv[i][2])
  1092.      {
  1093.          case DATAINFO:
  1094.             PlotInfo(docs, PlotData);
  1095.         break;
  1096.          case TYPEINFO:
  1097.         PlotInfo(types, PlotType);
  1098.         break;
  1099.          case WEEKDAYINFO:
  1100.         PlotInfo(days, PlotDay);
  1101.         break;
  1102.          case MONTHDATEINFO:
  1103.         PlotInfo(dates, PlotDate);
  1104.         break;
  1105.          case HOSTINFO:
  1106.         PlotInfo(hosts, PlotHost);
  1107.         break;
  1108.      }
  1109.       break;
  1110.       case 'w':
  1111.          if (i<argc-1)
  1112.         Width = atoi(argv[++i]) - WIDTHSUB;
  1113.      
  1114.      break;
  1115.       case 'o':
  1116.          if (i<argc-1)
  1117.         OutPlot = atoi(argv[++i]);
  1118.      break;
  1119.       case 'f':
  1120.          if (i<argc-1)
  1121.         base = argv[++i];
  1122.      break;
  1123.       case '?':
  1124.       case 'h':
  1125.          PrintHelp();
  1126.          break;
  1127.       default:
  1128.          fprintf(stderr, "Unknown option \"%c\" .  -h for help\n", argv[i][1]);
  1129.      break;
  1130.       } /*switch*/
  1131.     
  1132.       i++; /*next arg...*/
  1133.         
  1134.    } /*while*/
  1135.   
  1136.    exit(0);
  1137. }
  1138. /*******************************/
  1139.